#ifndef __M_EXCHANGE_H
#define __M_EXCHANGE_H

#include "../mqcommon/mq_logger.hpp"
#include "../mqcommon/mq_helper.hpp"
#include "../mqcommon/mq_msg.pb.h"
#include <google/protobuf/map.h>
#include <iostream>
#include <unordered_map>
#include <mutex>
#include <memory>

namespace lywmq
{

// 交换机类
struct Exchange
{
    using ptr = std::shared_ptr<Exchange>;

    std::string name; // 交换机名称
    ExchangeType type; // 交换机类型
    bool durable; // 持久化标志
    bool auto_delete; // 自动删除标志
    google::protobuf::Map<std::string, std::string> args; // 其它参数（该类型与后面的网络通信协议类型一致）
    Exchange()
    {}
    Exchange(const std::string& ename,
        ExchangeType etype,
        bool edurable,
        bool eauto_delete,
        const google::protobuf::Map<std::string, std::string> eargs)
    :name(ename), type(etype), durable(edurable), auto_delete(eauto_delete), args(eargs)
    {}
    // str_args是一个key=val&key=val...格式的字符串，该函数解析并存储到成员中
    void setArgs(const std::string& str_args) 
    {
        std::vector<std::string> sub_args;
        StrHelper::split(str_args, "&", sub_args);
        for (auto &str : sub_args)
        {
            size_t pos = str.find("=");
            std::string key = str.substr(0, pos);
            std::string val = str.substr(pos + 1);
            args[key] = val;
        }
    }
    std::string getArgs()
    {
        std::string result;
        for (auto start = args.begin(); start != args.end(); start++)
        {
            result += start->first + "=" + start->second + "&";
        }
        return result;
    }
};

using ExchangeMap = std::unordered_map<std::string, Exchange::ptr>;
// 交换机数据持久化管理类（数据存储在sqlite数据库中）
class ExchangeMapper
{
public:
    ExchangeMapper(const std::string& dbfile)
    :_sql_helper(dbfile)
    {
        std::string path = FileHelper::parentDirectory(dbfile);
        FileHelper::createDirectory(path);
        assert(_sql_helper.open());
        createTable();
    }
    void createTable()
    {
        std::stringstream ss;
        ss << "create table if not exists exchange_table(";
        ss << "name varchar(32) primary key, ";
        ss << "type int, ";
        ss << "durable int, ";
        ss << "auto_delete int, ";
        ss << "args varchar(128));";
        _sql_helper.exec(ss.str(), nullptr, nullptr);
    }
    void removeTable()
    {
        std::stringstream ss;
        ss << "drop table if exists exchange_table;";
        _sql_helper.exec(ss.str(), nullptr, nullptr);
    }
    bool insert(Exchange::ptr& exp)
    {
        std::stringstream ss;
        ss << "insert into exchange_table values(";
        ss << "'" << exp->name << "', ";
        ss << exp->type << ", ";
        ss << exp->durable << ", ";
        ss << exp->auto_delete << ", ";
        ss << "'" << exp->getArgs() << "');";
        return _sql_helper.exec(ss.str(), nullptr, nullptr);
    }
    void remove(const std::string& name)
    {
        std::stringstream ss;
        ss << "delete from exchange_table where name=";
        ss << "'" << name << "';";
        _sql_helper.exec(ss.str(), nullptr, nullptr);
    }
    // 恢复数据
    ExchangeMap recovery()
    {
        ExchangeMap result;
        std::string sql = "select name, type, durable, auto_delete, args from exchange_table;";
        _sql_helper.exec(sql, selectCallback, &result);
        return result;
    }
private:
    static int selectCallback(void* arg, int numcol, char** row, char** fields)
    {
        ExchangeMap* result = (ExchangeMap*)arg;
        Exchange::ptr exp = std::make_shared<Exchange>();
        exp->name = row[0];
        exp->type = (lywmq::ExchangeType)std::stoi(row[1]);
        exp->durable = (bool)std::stoi(row[2]);
        exp->auto_delete = (bool)std::stoi(row[3]);
        if (row[4]) exp->setArgs(row[4]);
        result->insert(std::make_pair(exp->name, exp));
        return 0; // 表示正常返回，回调函数无异常
    }
private:
    SqliteHelper _sql_helper;
};

// 交换机数据内存管理类
class ExchangeManager
{
public:
    using ptr = std::shared_ptr<ExchangeManager>;
    ExchangeManager(const std::string& dbfile)
    :_mapper(dbfile)
    {
        // 恢复数据
        _exchanges = _mapper.recovery();
    }
    // 声明交换机
    bool declareExchange(const std::string& name,
        ExchangeType type, bool durable, bool auto_delete,
        const google::protobuf::Map<std::string, std::string> args)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _exchanges.find(name);
        if (it != _exchanges.end())
            return true;

        Exchange::ptr exp = std::make_shared<Exchange>(name, type, durable, auto_delete, args);
        if (durable == true)
        {
            bool ret = _mapper.insert(exp);
            if (ret == false) return false;
        }
        _exchanges.insert(std::make_pair(name, exp));
        return true;
    }
    // 删除交换机
    void deleteExchange(const std::string& name)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _exchanges.find(name);
        if (it == _exchanges.end())
            return;
        if (it->second->durable == true)
            _mapper.remove(name);
        _exchanges.erase(name);
    }
    // 获取指定交换机对象
    Exchange::ptr selectExchange(const std::string& name)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _exchanges.find(name);
        if (it == _exchanges.end())
            return Exchange::ptr();
        return it->second;
    }
    // 判断交换机是否存在
    bool exists(const std::string& name)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _exchanges.find(name);
        if (it == _exchanges.end())
            return false;
        return true;
    }
    void clear()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _mapper.removeTable();
        _exchanges.clear();
    }
private:
    std::mutex _mutex;
    ExchangeMapper _mapper;
    ExchangeMap _exchanges;
};

}

#endif